package com.link.play.fit.ai.utils

import com.link.play.fit.ai.BuildConfig
import kotlinx.coroutines.*

const val TAG = "---"
private typealias L = android.util.Log

interface ILog {
    fun d(tag: String = TAG, msg: String = "", e: Throwable? = null) {}
    fun w(tag: String = TAG, msg: String = "", e: Throwable? = null) {}
    fun e(tag: String = TAG, msg: String = "", e: Throwable? = null, report: Boolean = false) {}
}

object LogX {

    val isDebug = BuildConfig.DEBUG

    private val logcat = Logcat(isDebug)
    private var log: ILog = logcat

    /**
     * 自定义 Log 实现
     * @param isOverride true 表示使用自定义实现覆盖默认实现, false 表示自定义实现和默认实现同时生效, 优先执行自定义实现
     */
    fun custom(vararg custom: ILog, isOverride: Boolean = false) {
        if (custom.isEmpty()) return
        log = if (isOverride) {
            if (custom.size == 1) {
                custom[0]
            } else {
                Logs(*custom)
            }
        } else {
            Logs(*custom, logcat)
        }
    }

    @JvmStatic
    fun d(tag: String = TAG, msg: String = "", e: Throwable? = null) {
        log.d(tag, msg, e)
    }

    @JvmStatic
    fun w(tag: String = TAG, msg: String = "", e: Throwable? = null) {
        log.w(tag, msg, e)
    }

    @JvmStatic
    fun e(tag: String = TAG, msg: String = "", e: Throwable? = null, report: Boolean = false) {
        log.e(tag, msg, e, report)
    }

    /* ---------------- method for java -- start -------------- */
    @JvmOverloads
    @JvmStatic
    @JvmName("d")
    fun javaD(msg: String = "", e: Throwable? = null) {
        d(msg = msg, e = e)
    }

    @JvmStatic
    @JvmName("d")
    fun javaD(tag: String, msg: String?) {
        d(tag = tag, msg = msg ?: "")
    }

    @JvmOverloads
    @JvmStatic
    @JvmName("w")
    fun javaW(msg: String = "", e: Throwable? = null) {
        w(msg = msg, e = e)
    }

    @JvmStatic
    @JvmName("w")
    fun javaW(tag: String, msg: String?) {
        w(tag = tag, msg = msg ?: "")
    }

    @JvmOverloads
    @JvmStatic
    @JvmName("e")
    fun javaE(msg: String = "", e: Throwable? = null) {
        e(msg = msg, e = e)
    }

    @JvmStatic
    @JvmName("e")
    fun javaE(e: Throwable?) {
        e(e = e)
    }

    @JvmStatic
    @JvmName("e")
    fun javaE(tag: String, msg: String?) {
        e(tag = tag, msg = msg ?: "")
    }
    /* ---------------- method for java -- end -------------- */
}

class Logcat(val printLog: Boolean = true) : ILog {
    override fun d(tag: String, msg: String, e: Throwable?) {
        if (!printLog) return
        if (e == null) {
            L.d(tag, msg)
        } else {
            L.d(tag, msg, e)
        }
    }

    override fun w(tag: String, msg: String, e: Throwable?) {
        if (!printLog) return
        if (e == null) {
            L.w(tag, msg)
        } else {
            L.w(tag, msg, e)
        }
    }

    override fun e(tag: String, msg: String, e: Throwable?, report: Boolean) {
        if (!printLog) return
        if (e == null) {
            L.e(tag, msg)
        } else {
            L.e(tag, msg, e)
        }
    }
}

class LogcatAsync(val printLog: Boolean = true) : ILog {

    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
    private val log = Logcat(printLog)

    override fun d(tag: String, msg: String, e: Throwable?) {
        if (!printLog) return
        scope.launch {
            log.d(tag, msg, e)
        }
    }

    override fun w(tag: String, msg: String, e: Throwable?) {
        if (!printLog) return
        scope.launch {
            log.w(tag, msg, e)
        }
    }

    override fun e(tag: String, msg: String, e: Throwable?, report: Boolean) {
        if (!printLog) return
        scope.launch {
            log.e(tag, msg, e, report)
        }
    }
}

private class Logs(private vararg val logs: ILog) : ILog {
    override fun d(tag: String, msg: String, e: Throwable?) {
        for (log in logs) {
            log.d(tag, msg, e)
        }
    }

    override fun w(tag: String, msg: String, e: Throwable?) {
        for (log in logs) {
            log.w(tag, msg, e)
        }
    }

    override fun e(tag: String, msg: String, e: Throwable?, report: Boolean) {
        for (log in logs) {
            log.e(tag, msg, e, report)
        }
    }
}